﻿

using Avalonia;
using LightCAD.MathLib;
using System.Linq;
using System.Reactive.Joins;
using System.Xml.Schema;
using GeometryData = LightCAD.Model.GeometryData;

namespace QdArch
{
    public class StairAction : ComponentInstance2dAction
    {
        private PointInputer PointInputer { get; set; }
        private QdStairInstance stairInstance = null;
        public StairAction() { }
        public StairAction(IDocumentEditor docEditor) : base(docEditor) 
        {
            this.commandCtrl.WriteInfo("命令：Stair");
        }
        public async void ExecCreate(string[] args = null)
        {
            this.PointInputer = new PointInputer(this.docEditor);
            var result = await this.PointInputer.Execute("请选择梯段起点:");
            if (result == null || result.ValueX == null || !(result.ValueX is Vector2) || this.PointInputer.isCancelled)
            {
                this.Cancel();
                goto End;
            }
            var startPoint= result.ValueX as Vector2;
            stairInstance = new QdStairInstance(ComponentManager.GetCptDef<QdStair>("楼梯", "双跑楼梯", StairAttribute.BuiltinUuid));
            stairInstance.Position.Set(startPoint.X, startPoint.Y, 0);
            stairInstance.StepHeight = 150;
            stairInstance.StepWidth = 260;
            stairInstance.StepNum = 1;
            stairInstance.LadderWidth = 1000;
            stairInstance.PlatLen = 2100;
            stairInstance.PlatWidth = 1200;
            stairInstance.PlatThickness = 500;
            stairInstance.SlabThickness = 100;
            stairInstance.StepThickness = 50;
            stairInstance.RiserThickness = 20;
            var result2 = await this.PointInputer.Execute("请选择梯段终点:");
            if (result2 == null || result2.ValueX == null || !(result2.ValueX is Vector2) || this.PointInputer.isCancelled)
            {
                this.Cancel();
                goto End;
            }
            var endPoint = result2.ValueX as Vector2;
            var len = startPoint.DistanceTo(endPoint);
            var stepNum = (int)Math.Floor(len / stairInstance.StepWidth);
            stairInstance.StepNum = len % stairInstance.StepWidth <0.5? stepNum: stepNum+1;
            var vec = endPoint.Clone().Sub(startPoint);
            var mat = new Matrix4();
            mat.MakeRotationZ(vec.Angle() - Math.PI / 2);
            stairInstance.Transform3d.Euler.SetFromRotationMatrix(mat);
            this.DrawStair(stairInstance);

        End:
            this.PointInputer = null;
            this.EndCreating();
        }
 
        //public async void ExecCreate(string[] args = null)
        //{
        //    //1. 选择插入点
        //    this.PointInputer = new PointInputer(this.docEditor);
        //    QdStairInstance stairInstance = null;
        //    var result = await this.PointInputer.Execute("插入点:");
        //    if (result == null || result.ValueX == null || !(result.ValueX is Vector2)||this.PointInputer.isCancelled)
        //    {
        //        this.Cancel();
        //        goto End;
        //    }
        //    var stairName = "DogleggedStair";
        //    //var stair = docRt.Document.Components.Find(ArchCategory.Stair.ToString(), stairName) as QdStair;
        //    //if (stair == null)
        //    //{
        //    //    stair = new QdStair(StairCategory.DogleggedStair.ToString(), stairName);
        //    //    docRt.Document.Components.Add(stair);
        //    //}
        //    //var stair = ComponentManager.GetCptDefs("楼梯", "双跑楼梯").FirstOrDefault();
        //    var stair = new QdStair();
        //    var instP = (Vector2)result.ValueX;
        //    stairInstance = new QdStairInstance(ComponentManager.GetCptDef<QdStair>("楼梯", "双跑楼梯", StairAttribute.BuiltinUuid));
        //    //stairInstance.Matrix = Matrix3.GetTranslate(instP);
        //    //stairInstance.Parameters = QdStair.ParamsDefinition.New();
        //    stairInstance.StepHeight = 150;
        //    stairInstance.StepWidth = 260;
        //    stairInstance.StepNum = 10;
        //    stairInstance.LadderWidth = 1000;
        //    stairInstance.PlatLen = 2100;
        //    stairInstance.PlatWidth = 1200;
        //    stairInstance.PlatThickness = 120;
        //    stairInstance.SlabThickness = 100;
        //    stairInstance.Position.Set(instP.X,instP.Y,0);
        //    this.DrawStair(stairInstance);

        ////stairInstance.stair = stair;
        //End:
        //    this.PointInputer = null;
        //    this.EndCreating();
        //}
        public override void Draw(SKCanvas canvas, LcElement element, Vector2 offset)
        {
            var stairInstance = element as QdStairInstance;
            var curves = stairInstance.Curves?.FirstOrDefault().Curve2ds;
            var pen = this.GetDrawPen(element);
            if (pen == LightCAD.Runtime.Constants.defaultPen)
            {
                pen = new SKPaint { Color = SKColors.White, IsStroke = true };
            }
            DrawStairCurves(canvas, curves, /*stairInstance.Matrix,*/ pen);
        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {
            var stairInstance = element as QdStairInstance;
            // var curves = stairInstance.ShapeCurves;
            var curves = stairInstance.Curves?.FirstOrDefault().Curve2ds;
            var pen = this.GetDrawPen(element);
            if (pen == LightCAD.Runtime.Constants.defaultPen)
            {
                pen = new SKPaint { Color = SKColors.White, IsStroke = true };
            }
            //matrix = matrix * stairInstance.Matrix;
            DrawStairCurves(canvas, curves, /*matrix, */pen);
        }
        //public void DrawStairCurves(SKCanvas canvas, List<Curve2d> curves, Matrix3 matrix, SKPaint pen)
        public void DrawStairCurves(SKCanvas canvas, List<Curve2d> curves,  SKPaint pen)
        {
            foreach (var curve in curves)
            {
                switch (curve.Type)
                {
                    case Curve2dType.Rect2d:
                        {
                            var rect = curve as Rect2d;
                            var points = rect.GetPoints().Select(n=> this.vportRt.ConvertWcsToScr(n).ToSKPoint()).ToList();
                            points.Add(points.First());
                            //var min = rect.Min;
                            //var max = rect.Max; 
                            //var a = this.vportRt.ConvertWcsToScr(min).ToSKPoint();
                            //var b = this.vportRt.ConvertWcsToScr(new Vector2(max.X, min.Y)).ToSKPoint();
                            //var c = this.vportRt.ConvertWcsToScr(max).ToSKPoint();
                            //var d = this.vportRt.ConvertWcsToScr(new Vector2(min.X, max.Y)).ToSKPoint();
                            canvas.DrawPoints(SKPointMode.Polygon, points.ToArray(), pen);
                            break;
                        }
                    default:
                        break;
                }
            }
        }

        private void DrawStair(QdStairInstance stairInstance) 
        {
            if (stairInstance == null)
                return;
            stairInstance.Initilize(this.docRt.Document);
            this.docRt.Document.ModelSpace.InsertElement(stairInstance);
        }
        public override void Cancel()
        {
            base.Cancel();
            this.vportRt.SetCreateDrawer(null);
        }

        #region Grip
        private QdStairInstance _stairInstance;
        private string _gripName;
        private Vector2 _position;

        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var stairInstance = element as QdStairInstance;
            var grips = new List<ControlGrip>();

            var gripInsert = new ControlGrip
            {
                Element = stairInstance,
                Name = "InsertPoint",
                Position = stairInstance.Position.ToVector2()
            };
            grips.Add(gripInsert);
            return grips.ToArray();
        }

        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            var stairInstance = element as QdStairInstance;
            _stairInstance = stairInstance;
            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
                if (gripName == "InsertPoint")
                {
                    var offset = position.Clone().Sub(stairInstance.Position.ToVector2());
                    stairInstance.Translate(offset);
                    //stairInstance.Matrix = Matrix3.GetTranslate(offset)*stairInstance.Matrix ;
                }
            }
            else
            {
            }

        }
        public override List<PropertyObserver> GetPropertyObservers()
        {
            //return base.GetPropertyObservers();
            return new List<PropertyObserver>() {
             new PropertyObserver()
            {
                Name = "StepHeight",
                DisplayName = "踏步高度",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Double,
                Getter = (ele) => (ele as QdStairInstance).Parameters.GetValue<double>("StepHeight"),
                Setter = (ele, value) =>
                {
                    var stair = (ele as QdStairInstance);
                    if (!double.TryParse(value.ToString(),out var stepHeight)||stepHeight<0)
                        return;
                    stair.OnPropertyChangedBefore("StepHeight",stair.Parameters.GetValue<double>("StepHeight"),stepHeight);
                    stair.Parameters.SetValue("StepHeight",stepHeight );
                    stair.ResetCache();
                    stair.OnPropertyChangedAfter("StepHeight",stair.Parameters.GetValue<double>("StepHeight"),stepHeight);
                }
            },
            new PropertyObserver()
            {
                Name = "StepWidth",
                DisplayName = "踏步宽度",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Double,
                Getter = (ele) => (ele as QdStairInstance).Parameters.GetValue<double>("StepWidth"),
                Setter = (ele, value) =>
                {
                    var stair = (ele as QdStairInstance);
                    if (!double.TryParse(value.ToString(),out var stepWidth)||stepWidth<0)
                        return;
                    stair.OnPropertyChangedBefore("StepWidth",stair.Parameters.GetValue<double>("StepWidth"),stepWidth);
                    stair.Parameters.SetValue("StepWidth",stepWidth );
                    stair.ResetCache();
                    stair.OnPropertyChangedAfter("StepWidth",stair.Parameters.GetValue<double>("StepWidth"),stepWidth);
                }
            },
            new PropertyObserver()
            {
                Name = "StepNum",
                DisplayName = "踏步数",
                CategoryName = "StepNum",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Int,
                Getter = (ele) => (ele as QdStairInstance).Parameters.GetValue<int>("StepNum"),
                Setter = (ele, value) =>
                {
                    var stair = (ele as QdStairInstance);
                    if (!int.TryParse(value.ToString(),out var stepNum)||stepNum <0)
                        return;
                    stair.OnPropertyChangedBefore("StepNum",stair.Parameters.GetValue<int>("StepNum"),stepNum);
                    stair.Parameters.SetValue("StepNum",stepNum );
                    stair.ResetCache();
                    stair.OnPropertyChangedAfter("StepNum",stair.Parameters.GetValue<int>("StepNum"),stepNum);
                }
            },
             new PropertyObserver()
            {
                Name = "PlatWidth",
                DisplayName = "平台宽度",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Double,
                Getter = (ele) => (ele as QdStairInstance).Parameters.GetValue<double>("PlatWidth"),
                Setter = (ele, value) =>
                {
                    var stair = (ele as QdStairInstance);
                    if (!double.TryParse(value.ToString(),out var platWidth)||platWidth<0)
                        return;
                    stair.OnPropertyChangedBefore("PlatWidth",stair.Parameters.GetValue<double>("PlatWidth"),platWidth);
                    stair.Parameters.SetValue("PlatWidth",platWidth );
                    stair.ResetCache();
                    stair.OnPropertyChangedAfter("PlatWidth",stair.Parameters.GetValue<double>("PlatWidth"),platWidth);
                }
            },
             new PropertyObserver()
            {
                Name = "PlatLen",
                DisplayName = "平台长度",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Double,
                Getter = (ele) => (ele as QdStairInstance).Parameters.GetValue<double>("PlatLen"),
                Setter = (ele, value) =>
                {
                    var stair = (ele as QdStairInstance);
                    if (!double.TryParse(value.ToString(),out var platLen)||platLen<0)
                        return;
                    stair.OnPropertyChangedBefore("PlatLen",stair.Parameters.GetValue<double>("PlatLen"),platLen);
                    stair.Parameters.SetValue("PlatLen",platLen );
                    stair.ResetCache();
                    stair.OnPropertyChangedAfter("PlatLen",stair.Parameters.GetValue<double>("PlatLen"),platLen);
                }
            },
             new PropertyObserver()
            {
                Name = "PlatThickness",
                DisplayName = "平台厚度",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Double,
                Getter = (ele) => (ele as QdStairInstance).Parameters.GetValue<double>("PlatThickness"),
                Setter = (ele, value) =>
                {
                    var stair = (ele as QdStairInstance);
                    if (!double.TryParse(value.ToString(),out var platThickness)||platThickness<0)
                        return;
                    stair.OnPropertyChangedBefore("PlatThickness",stair.Parameters.GetValue<double>("PlatThickness"),platThickness);
                    stair.Parameters.SetValue("PlatThickness",platThickness );
                    stair.ResetCache();
                    stair.OnPropertyChangedAfter("PlatThickness",stair.Parameters.GetValue<double>("PlatThickness"),platThickness);
                }
            }
             ,
             new PropertyObserver()
            {
                Name = "SlabThickness",
                DisplayName = "梯段板厚",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Double,
                Getter = (ele) => (ele as QdStairInstance).Parameters.GetValue<double>("SlabThickness"),
                Setter = (ele, value) =>
                {
                    var stair = (ele as QdStairInstance);
                    if (!double.TryParse(value.ToString(),out var slabThickness)||slabThickness<0)
                        return;
                    stair.OnPropertyChangedBefore("SlabThickness",stair.Parameters.GetValue<double>("SlabThickness"),slabThickness);
                    stair.Parameters.SetValue("SlabThickness",slabThickness );
                    stair.ResetCache();
                    stair.OnPropertyChangedAfter("SlabThickness",stair.Parameters.GetValue<double>("SlabThickness"),slabThickness);
                }
            },
             new PropertyObserver()
            {
                Name = "LadderWidth",
                DisplayName = "踏步长度",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Double,
                Getter = (ele) => (ele as QdStairInstance).Parameters.GetValue<double>("LadderWidth"),
                Setter = (ele, value) =>
                {
                    var stair = (ele as QdStairInstance);
                    if (!double.TryParse(value.ToString(),out var ladderWidth)||ladderWidth<0)
                        return;
                    stair.OnPropertyChangedBefore("LadderWidth",stair.Parameters.GetValue<double>("LadderWidth"),ladderWidth);
                    stair.Parameters.SetValue("LadderWidth",ladderWidth );
                    stair.ResetCache();
                    stair.OnPropertyChangedAfter("LadderWidth",stair.Parameters.GetValue<double>("LadderWidth"),ladderWidth);
                }
            },
              new PropertyObserver()
            {
                Name = "StepThickness",
                DisplayName = "踏步厚度",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Double,
                Getter = (ele) => (ele as QdStairInstance).Parameters.GetValue<double>("StepThickness"),
                Setter = (ele, value) =>
                {
                    var stair = (ele as QdStairInstance);
                    if (!double.TryParse(value.ToString(),out var stepThickness)||stepThickness<0)
                        return;
                    stair.OnPropertyChangedBefore("StepThickness",stair.Parameters.GetValue<double>("StepThickness"),stepThickness);
                    stair.Parameters.SetValue("StepThickness",stepThickness );
                    stair.ResetCache();
                    stair.OnPropertyChangedAfter("StepThickness",stair.Parameters.GetValue<double>("StepThickness"),stepThickness);
                }
            },
               new PropertyObserver()
            {
                Name = "RiserThickness",
                DisplayName = "踢面厚度",
                CategoryName = "Geometry",
                CategoryDisplayName = "几何图形",
                PropType=PropertyType.Double,
                Getter = (ele) => (ele as QdStairInstance).Parameters.GetValue<double>("RiserThickness"),
                Setter = (ele, value) =>
                {
                    var stair = (ele as QdStairInstance);
                    if (!double.TryParse(value.ToString(),out var riserThickness)||riserThickness<0)
                        return;
                    stair.OnPropertyChangedBefore("RiserThickness",stair.Parameters.GetValue<double>("RiserThickness"),riserThickness);
                    stair.Parameters.SetValue("RiserThickness",riserThickness );
                    stair.ResetCache();
                    stair.OnPropertyChangedAfter("RiserThickness",stair.Parameters.GetValue<double>("RiserThickness"),riserThickness);
                }
            },
            };
        }
        public override void DrawDragGrip(SKCanvas canvas)
        {
            if (_stairInstance == null)
                return;
            if (_gripName == "InsertPoint")
            {
                var offset = _position - _stairInstance.Position.ToVector2();
              //  var matrix = Matrix3.GetTranslate(offset) * _stairInstance.Matrix;
                var curves = _stairInstance.Curves;
                DrawStairCurves(canvas, curves?.FirstOrDefault().Curve2ds,/* matrix,*/ LightCAD.Runtime.Constants.draggingPen);
            }

        }
        #endregion

    }
    public class Stair3dAction : ComponentInstance3dAction
    {
        public override List<Object3D> Render(IComponentInstance cptIns)
        {
            try
            {
                var stair = cptIns as QdStairInstance;
                var laddergeo = CreateLadder(stair.StepHeight, stair.StepNum, stair.StepWidth, stair.LadderWidth, stair.SlabThickness, -stair.PlatThickness, 0);
                var laddergeo2 = CreateLadder(stair.StepHeight, stair.StepNum, stair.StepWidth, stair.LadderWidth, stair.SlabThickness,  0, -stair.PlatThickness );
                laddergeo2.rotateZ(-MathUtil.Pi).translateQuick(stair.PlatLen, stair.StepNum * stair.StepWidth, (stair.StepNum + 1) * stair.StepHeight);
                //var laddergeo2 = laddergeo.clone()

                var plat = CreatePlat(stair.StepHeight, stair.StepNum, stair.StepWidth, stair.LadderWidth, stair.SlabThickness, stair.PlatLen, stair.PlatWidth, stair.PlatThickness);
                //var plat2 = CreatePlat(stair.PlatLen, stair.PlatWidth, stair.PlatThickness);
                //plat2.translateQuick(0, -stair.PlatWidth, 0);
                //var plat3 = plat2.clone().translateQuick(0, 0, stair.StepNum * stair.StepHeight * 2);
                plat.translateQuick(0, stair.StepNum * stair.StepWidth, (stair.StepNum + 1) * stair.StepHeight - stair.PlatThickness);
                var geos = new List<BufferGeometry> { laddergeo, laddergeo2, plat };
                var ladderStep = CreateLadderStep(stair.StepWidth, stair.LadderWidth, stair.StepThickness);
                var ladderRiser = CreateRiser(stair.StepHeight, stair.LadderWidth, stair.RiserThickness);
                for (var i = 0; i < stair.StepNum; i++)
                {
                    if (stair.StepThickness > 0)
                    {
                        geos.Add(ladderStep.clone().translateQuick(0, i * stair.StepWidth- stair.RiserThickness, (i + 1) * stair.StepHeight ));
                        geos.Add(ladderStep.clone().translateQuick(stair.PlatLen - stair.LadderWidth, (stair.StepNum - i - 1) * stair.StepWidth + stair.RiserThickness, (stair.StepNum + i + 2) * stair.StepHeight ));
                    }
                    if (stair.RiserThickness > 0)
                    {
                        geos.Add(ladderRiser.clone().translateQuick(stair.PlatLen - stair.LadderWidth, (stair.StepNum - i) * stair.StepWidth, (stair.StepNum + i + 2) * stair.StepHeight ));
                        geos.Add(ladderRiser.clone().translateQuick(0, i * stair.StepWidth- stair.RiserThickness, (i + 1) * stair.StepHeight));
                        if (i == stair.StepNum - 1)
                        {
                            geos.Add(ladderRiser.clone().translateQuick(stair.PlatLen - stair.LadderWidth, 0, (stair.StepNum * 2 + 2) * stair.StepHeight  ));
                            geos.Add(ladderRiser.clone().translateQuick(0, stair.StepNum * stair.StepWidth- stair.RiserThickness, (stair.StepNum + 1) * stair.StepHeight  ));
                        }
                    }
                }
                if (stair.StepThickness > 0)
                {
                    var platStep = CreatePlatStep(stair.PlatLen, stair.PlatWidth, stair.StepThickness,stair.LadderWidth,stair.RiserThickness);
                    geos.Add(platStep.translateQuick(0, stair.StepNum * stair.StepWidth, (stair.StepNum + 1) * stair.StepHeight ));
                }
                var ptx = CreatePTX(stair.StepHeight, stair.StepNum, stair.StepWidth, stair.LadderWidth, stair.PlatLen, stair.PlatWidth, stair.StepThickness, stair.RiserThickness);

                geos.Add(ptx);
                var lcMats = stair.Definition.Solid3dProvider.AssignMaterialsFunc(cptIns, null);
                var result = new List<Object3D>();
                foreach (var geo in geos)
                {
                    geo.computeVertexNormals();
                    geo.SetUV();
                    Material material;
                    if (geo.name=="Plat"||geo.name== "Ladder")
                    {
                        material = RenderMaterialManager.GetRenderMaterial(lcMats[1].Uuid);
                    }
                    else if (geo.name == "PTX")
                    {
                        material = RenderMaterialManager.GetRenderMaterial(lcMats[2].Uuid);
                    }
                    else
                    {
                        material = RenderMaterialManager.GetRenderMaterial(lcMats[0].Uuid);
                    }
                    var mesh = new Mesh(geo, material);
                    mesh.setRotationFromEuler(stair.Transform3d.Euler);
                    mesh.position.Set(stair.Transform3d.Position.X, stair.Transform3d.Position.Y, 0);
                    result.Add(mesh);
                }
                return result;
            }
            catch (Exception ex)
            {

            }
            return this.Render(cptIns);
        }
        private LightCAD.Three.BufferGeometry CreatePTX(double stepHeight, int stepNum, double stepWidth, double ladderLen,  double len, double width, double stepThickness, double riserThickness)
        {
            var ptxHeight = 2200;//碰头线高度
            var blCurves=new List<Curve3d>();//下梯段左侧碰头线 
            var tlCurves = new List<Curve3d>();//上梯段左侧碰头线 
            var trCurves = new List<Curve3d>();//上梯段左侧碰头线 
            var surfaces = new List<Surface3d>();
            for (int i = 0; i < stepNum; i++)
            {
                var lStepCurves = new List<Curve3d>();//踏步碰头线
                var lRiserCurves = new List<Curve3d>();//踢面碰头线
                lStepCurves.Add(new Line3d(new Vector3(0, i * stepWidth - riserThickness, stepHeight * (i + 1)+stepThickness), new Vector3(ladderLen, i * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness)));
                lStepCurves.Add(new Line3d(new Vector3(ladderLen, i * stepWidth - riserThickness, stepHeight * (i + 1)+stepThickness), new Vector3(ladderLen, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness)));
                lStepCurves.Add(new Line3d(new Vector3(ladderLen, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness), new Vector3(0, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness)));
                lStepCurves.Add(new Line3d(new Vector3(0, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness), new Vector3(0, i * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness)));

                lRiserCurves.Add(new Line3d(new Vector3(ladderLen, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness), new Vector3(0, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness)));
                lRiserCurves.Add(new Line3d(new Vector3(0, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness), new Vector3(0, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 2) + stepThickness)));
                lRiserCurves.Add(new Line3d(new Vector3(0, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 2) + stepThickness), new Vector3(ladderLen, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 2) + stepThickness)));
                lRiserCurves.Add(new Line3d(new Vector3(ladderLen, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 2) + stepThickness), new Vector3(ladderLen, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness)));
                
                var rStepCurves = lStepCurves.Select(n => n.Clone().Translate(len-ladderLen  , riserThickness*2, stepHeight*2*(stepNum-i))).ToList();
                var rRiserCurves = lRiserCurves.Select(n => n.Clone().Translate(len - ladderLen, riserThickness * 2, stepHeight *  (2*stepNum - 2*i-1))).ToList();
                surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, 0, -1)), lStepCurves));
                surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, 0, -1)), rStepCurves));
                surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, 1, 0)), lRiserCurves));
                surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, -1, 0)), rRiserCurves));
                blCurves.Add(new Line3d(new Vector3(0, i * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness), new Vector3(0, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness)));
                blCurves.Add(new Line3d(new Vector3(0, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 1) + stepThickness), new Vector3(0, (i + 1) * stepWidth - riserThickness, stepHeight * (i + 2) + stepThickness)));

                tlCurves.Add(new Line3d(new Vector3(len - ladderLen, i * stepWidth + riserThickness, stepHeight * (2* stepNum + 1 -i) + stepThickness), new Vector3(len - ladderLen, (i + 1) * stepWidth + riserThickness, stepHeight * (2 * stepNum + 2 - i) + stepThickness)));
                tlCurves.Add(new Line3d(new Vector3(len - ladderLen, (i + 1) * stepWidth + riserThickness, stepHeight * (2 * stepNum + 1 - i) + stepThickness), new Vector3(len - ladderLen, (i + 1) * stepWidth + riserThickness, stepHeight * (2 * stepNum +1 - i) + stepThickness)));
            }
            //if (riserThickness > 0)
            //{
            //    var oldFirst = tlCurves.First().Start.Clone();
            //    var firstP = oldFirst.Clone().Add(new Vector3(0, 0, stepHeight));
            //    tlCurves.Insert(0,new Line3d(firstP.Clone().Add(new Vector3(0,0, 0)), firstP));
            //    tlCurves.Insert(1, new Line3d(firstP, oldFirst));
            //}
            var bltCurves = new List<Curve3d>();//下梯段左侧顶部碰头线 
            var blLast= blCurves.Last().End.Clone().Add(new Vector3(0,0,ptxHeight));
            var blFirst = blCurves.First().Start.Clone().Add(new Vector3(0, 0, ptxHeight));
            var btCurves = new List<Curve3d>();//下梯段顶部碰头线 
            var brCurves = blCurves.Select(n => n.Clone().Translate(ladderLen, 0, 0)).ToList();//下梯段右侧碰头线 
            var bfCurves = new List<Curve3d>();//下梯段正面入口碰头线 
            var platBottomCurves = new List<Curve3d>();//平台底部碰头线
            var platBackCurves = new List<Curve3d>();//平台背部碰头线
            var platTopCurves = new List<Curve3d>();//平台顶部碰头线
            //var platFrontCurves = new List<Curve3d>();//平台正面碰头线
            var platTlCurves = new List<Curve3d>();//平台顶部接下梯段碰头线
            var platTrCurves = new List<Curve3d>();//平台顶部接上梯段碰头线
            var platTlrCurves = new List<Curve3d>();//平台顶部下梯段接上梯段碰头线
            var platBlCurves = new List<Curve3d>();//平台顶部下梯段连接背面碰头线
            var platBrCurves = new List<Curve3d>();//平台顶部上梯段连接背面碰头线
            var platFlCurves = new List<Curve3d>();//平台正面左侧碰头线
            var platFrCurves = new List<Curve3d>();//平台正面右侧碰头线
            var platFlrCurves = new List<Curve3d>();//平台正面左右连接碰头线
            btCurves.Add(new Line3d(blLast.Clone(),blFirst.Clone()));
            btCurves.Add(new Line3d(blFirst.Clone(), brCurves.First().Start.Clone().Add(new Vector3(0, 0, ptxHeight))));
            btCurves.Add(new Line3d(brCurves.First().Start.Clone().Add(new Vector3(0, 0, ptxHeight)), brCurves.Last().End.Clone().Add(new Vector3(0, 0, ptxHeight))));
            btCurves.Add(new Line3d(brCurves.Last().End.Clone().Add(new Vector3(0, 0, ptxHeight)), blFirst.Clone()));

            bfCurves.Add(new Line3d(blCurves.First().Start.Clone(), blFirst.Clone()));
            bfCurves.Add(new Line3d(blFirst.Clone(), brCurves.First().Start.Clone().Add(new Vector3(0, 0, ptxHeight))));
            bfCurves.Add(new Line3d(brCurves.First().Start.Clone().Add(new Vector3(0, 0, ptxHeight)), brCurves.First().Start.Clone()));
            bfCurves.Add(new Line3d(brCurves.First().Start.Clone(), blFirst.Clone()));

            platFlCurves.Add(new Line3d(brCurves.Last().End.Clone(), brCurves.Last().End.Clone().Add(new Vector3(0, 0, ptxHeight))));
            platFlCurves.Add(new Line3d(brCurves.Last().End.Clone().Add(new Vector3(0, 0, ptxHeight)), brCurves.Last().End.Clone().Add(new Vector3(len / 2 - ladderLen, 0, ptxHeight))));
            platFlCurves.Add(new Line3d(brCurves.Last().End.Clone().Add(new Vector3(len / 2 - ladderLen, 0, ptxHeight)), brCurves.Last().End.Clone().Add(new Vector3(len / 2 - ladderLen, 0, 0))));
            platFlCurves.Add(new Line3d(brCurves.Last().End.Clone().Add(new Vector3(len / 2 - ladderLen, 0, 0)), brCurves.Last().End.Clone()));

            platFrCurves.Add(new Line3d(tlCurves.Last().End.Clone().Add(new Vector3(0,0,-stepHeight)), tlCurves.Last().End.Clone().Add(new Vector3(0, 0, ptxHeight))));
            platFrCurves.Add(new Line3d(tlCurves.Last().End.Clone().Add(new Vector3(0, 0, ptxHeight)), tlCurves.Last().End.Clone().Add(new Vector3(ladderLen -len / 2 , 0, ptxHeight))));
            platFrCurves.Add(new Line3d(tlCurves.Last().End.Clone().Add(new Vector3(ladderLen - len / 2, 0, ptxHeight)), tlCurves.Last().End.Clone().Add(new Vector3(ladderLen - len / 2, 0, -stepHeight))));
            platFrCurves.Add(new Line3d(tlCurves.Last().End.Clone().Add(new Vector3(ladderLen - len / 2, 0, -stepHeight)), tlCurves.Last().End.Clone().Add(new Vector3(0, 0, -stepHeight))));

            platFlrCurves.Add(new Line3d(brCurves.Last().End.Clone().Add(new Vector3(len / 2 - ladderLen, 0, 0)), brCurves.Last().End.Clone().Add(new Vector3(len / 2 - ladderLen, 0, ptxHeight))));
            platFlrCurves.Add(new Line3d(brCurves.Last().End.Clone().Add(new Vector3(len / 2 - ladderLen, 0, ptxHeight)), brCurves.Last().End.Clone().Add(new Vector3(len / 2 - ladderLen, riserThickness * 2, ptxHeight))));
            platFlrCurves.Add(new Line3d(brCurves.Last().End.Clone().Add(new Vector3(len / 2 - ladderLen, riserThickness * 2, ptxHeight)), brCurves.Last().End.Clone().Add(new Vector3(len / 2 - ladderLen, riserThickness * 2, 0))));
            platFlrCurves.Add(new Line3d(brCurves.Last().End.Clone().Add(new Vector3(len / 2 - ladderLen, riserThickness * 2, 0)), brCurves.Last().End.Clone().Add(new Vector3(len / 2 - ladderLen, 0, 0))));

            //brCurves.Add(new Line3d(brCurves.Last().End.Clone(), brCurves.Last().End.Clone().Add(new Vector3(0, riserThickness, 0))));
            brCurves.Add(new Line3d(brCurves.Last().End.Clone(), brCurves.Last().End.Clone().Add(new Vector3(0, 0, ptxHeight))));
            //brCurves.Add(new Line3d(brCurves.Last().End.Clone(), brCurves.Last().End.Clone().Add(new Vector3(0, -riserThickness, 0))));
            brCurves.Add(new Line3d(brCurves.Last().End.Clone(), brCurves.First().Start.Clone().Add(new Vector3(0, 0, ptxHeight))));
            brCurves.Add(new Line3d(brCurves.Last().End.Clone(), brCurves.First().Start.Clone()));

            //platBottomCurves.Add(new Line3d(blCurves.Last().End.Clone(), blCurves.Last().End.Clone().Add(new Vector3(ladderLen,0,0))));
            //platBottomCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(ladderLen, 0, 0)), blCurves.Last().End.Clone().Add(new Vector3(ladderLen, riserThickness, 0))));
            //platBottomCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(ladderLen, riserThickness, 0)), blCurves.Last().End.Clone().Add(new Vector3(len - ladderLen, riserThickness, 0))));
            //platBottomCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(len - ladderLen, riserThickness, 0)), blCurves.Last().End.Clone().Add(new Vector3(len - ladderLen, riserThickness*2, 0))));
            //platBottomCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(len - ladderLen, riserThickness*2, 0)), blCurves.Last().End.Clone().Add(new Vector3(len, riserThickness * 2, 0))));
            platBottomCurves.Add(new Line3d(blCurves.Last().End.Clone(), blCurves.Last().End.Clone().Add(new Vector3(len/2, 0, 0))));
            platBottomCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(len / 2, 0, 0)), blCurves.Last().End.Clone().Add(new Vector3(len / 2, riserThickness*2, 0))));
            platBottomCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(len / 2, riserThickness * 2, 0)), blCurves.Last().End.Clone().Add(new Vector3(len , riserThickness * 2, 0))));
            platBottomCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(len , riserThickness * 2, 0)), blCurves.Last().End.Clone().Add(new Vector3(len, riserThickness + width , 0))));
            platBottomCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(len, riserThickness + width, 0)), blCurves.Last().End.Clone().Add(new Vector3(0, riserThickness + width, 0))));
            platBottomCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(0, riserThickness + width, 0)), blCurves.Last().End.Clone()));

            platBackCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(len, width+riserThickness, 0)), blCurves.Last().End.Clone().Add(new Vector3(0, width + riserThickness, 0))));
            platBackCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(0, width + riserThickness, 0)), blCurves.Last().End.Clone().Add(new Vector3(0, width + riserThickness, ptxHeight - 200))));
            platBackCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(0, width + riserThickness, ptxHeight - 200)), blCurves.Last().End.Clone().Add(new Vector3(len, width + riserThickness, ptxHeight - 200))));
            platBackCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(len, width + riserThickness, ptxHeight - 200)), blCurves.Last().End.Clone().Add(new Vector3(len, width + riserThickness, 0))));

            platTopCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(0,stepWidth, ptxHeight - 200)), blCurves.Last().End.Clone().Add(new Vector3(len/2, stepWidth, ptxHeight - 200))));
            platTopCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(len/2, stepWidth, ptxHeight - 200)), blCurves.Last().End.Clone().Add(new Vector3(len/2, stepWidth+riserThickness*2, ptxHeight - 200))));
            platTopCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(len / 2, stepWidth + riserThickness * 2, ptxHeight - 200)), blCurves.Last().End.Clone().Add(new Vector3(len, stepWidth + riserThickness * 2, ptxHeight - 200))));
            platTopCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(len, stepWidth + riserThickness * 2, ptxHeight - 200)), blCurves.Last().End.Clone().Add(new Vector3(len, width + riserThickness , ptxHeight - 200))));
            platTopCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(len, width + riserThickness, ptxHeight - 200)), blCurves.Last().End.Clone().Add(new Vector3(0, width + riserThickness, ptxHeight - 200))));
            platTopCurves.Add(new Line3d(blCurves.Last().End.Clone().Add(new Vector3(0, width + riserThickness, ptxHeight - 200)), blCurves.Last().End.Clone().Add(new Vector3(0, stepWidth, ptxHeight - 200))));

            //platFrontCurves.Add(new Line3d(brLast.Clone(), brLast.Clone().Add(new Vector3((len - 2 * ladderLen) / 2, 0, 0))));
            //platFrontCurves.Add(new Line3d(brLast.Clone().Add(new Vector3((len - 2 * ladderLen) / 2, 0, 0)), brLast.Clone().Add(new Vector3((len - 2 * ladderLen) / 2, 0, stepHeight))));
            //platFrontCurves.Add(new Line3d(brLast.Clone().Add(new Vector3((len - 2 * ladderLen) / 2, 0, stepHeight)), brLast.Clone().Add(new Vector3(len - 2 * ladderLen, 0, stepHeight))));
            //platFrontCurves.Add(new Line3d(brLast.Clone().Add(new Vector3(len - 2 * ladderLen, 0, stepHeight)), brLast.Clone().Add(new Vector3(len - 2 * ladderLen, 0, -ptxHeight))));
            //platFrontCurves.Add(new Line3d(brLast.Clone().Add(new Vector3(len - 2 * ladderLen, 0, -ptxHeight)), brLast.Clone().Add(new Vector3(0, 0, -ptxHeight))));
            //platFrontCurves.Add(new Line3d(brLast.Clone().Add(new Vector3(0, 0, -ptxHeight)), brLast.Clone()));

            platTlCurves.Add(new Line3d(blLast.Clone(), blLast.Clone().Add(new Vector3(len/2,0,0))));
            platTlCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len / 2, 0, 0)), blLast.Clone().Add(new Vector3(len / 2,stepWidth, 0))));
            platTlCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len / 2, stepWidth, 0)), blLast.Clone().Add(new Vector3(0, stepWidth, 0))));
            platTlCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(0, stepWidth, 0)), blLast.Clone()));
            
            platTrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len / 2, riserThickness*2 , stepHeight)), blLast.Clone().Add(new Vector3(len , riserThickness * 2, stepHeight))));
            platTrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len, riserThickness * 2, stepHeight)), blLast.Clone().Add(new Vector3(len, riserThickness * 2 + stepWidth, stepHeight))));
            platTrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len, riserThickness * 2 + stepWidth, stepHeight)), blLast.Clone().Add(new Vector3(len / 2, riserThickness * 2 + stepWidth, stepHeight))));
            platTrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len / 2, riserThickness * 2 + stepWidth, stepHeight)), new Vector3(len / 2, riserThickness * 2, stepHeight)));

            platBlCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(0, stepWidth, 0)), blLast.Clone().Add(new Vector3(len / 2, stepWidth, 0))));
            platBlCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len / 2, stepWidth, 0)), blLast.Clone().Add(new Vector3(len / 2, stepWidth, -200))));
            platBlCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len / 2, stepWidth, -200)), blLast.Clone().Add(new Vector3(0, stepWidth, -200))));
            platBlCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(0, stepWidth, -200)), blLast.Clone().Add(new Vector3(0, stepWidth,0))));

            platBrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len/2, riserThickness * 2 + stepWidth, stepHeight)), blLast.Clone().Add(new Vector3(len, riserThickness * 2 + stepWidth, stepHeight))));
            platBrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len, riserThickness * 2 + stepWidth, stepHeight)), blLast.Clone().Add(new Vector3(len, riserThickness * 2 + stepWidth, -200))));
            platBrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len, riserThickness * 2 + stepWidth, -200)), blLast.Clone().Add(new Vector3(len/2, riserThickness * 2 + stepWidth,  - 200))));
            platBrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len/2, riserThickness * 2 + stepWidth,  - 200)), blLast.Clone().Add(new Vector3(len / 2, riserThickness * 2 + stepWidth, stepHeight ))));

            platTlrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len / 2, riserThickness * 2, 0)), blLast.Clone().Add(new Vector3(len / 2, riserThickness * 2, stepHeight))));
            platTlrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len / 2, riserThickness * 2, stepHeight)), blLast.Clone().Add(new Vector3(len / 2, stepWidth+ riserThickness * 2, stepHeight))));
            platTlrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len / 2, stepWidth+ riserThickness * 2, stepHeight)), blLast.Clone().Add(new Vector3(len / 2, stepWidth + riserThickness * 2, -200))));
            platTlrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len / 2, stepWidth + riserThickness * 2, -200)), blLast.Clone().Add(new Vector3(len / 2, stepWidth, -200))));
            platTlrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len / 2, stepWidth , -200)), blLast.Clone().Add(new Vector3(len / 2, stepWidth, 0))));
            platTlrCurves.Add(new Line3d(blLast.Clone().Add(new Vector3(len / 2, stepWidth, 0)), blLast.Clone().Add(new Vector3(len / 2, riserThickness * 2, 0))));



            surfaces.Add(new PlanarSurface3d(new Plane(blFirst.Clone().Sub(blLast).Cross(new Vector3(1,0,0)).Normalize()), btCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, -1, 0)), bfCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(1, 0, 0)), brCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, 0, -1)), platBottomCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, 1, 0)), platBackCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, 0, 1)), platTopCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, -1, 0)), platFrCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, -1, 0)), platFlCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, 0, 1)), platTlCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, 0, 1)), platTrCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(-1, 0, 0)), platTlrCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, 1, 0)), platBrCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, 1, 0)), platBlCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(1, 0, 0)), platFlrCurves));

            bltCurves.Add(new Line3d(blFirst,blLast.Clone()));
            bltCurves.Add(new Line3d(blLast.Clone(), blLast.Add(new Vector3(0, stepWidth, 0)).Clone()));
            bltCurves.Add(new Line3d(blLast.Clone(), blLast.Add(new Vector3(0, 0, - 200)).Clone()));
            bltCurves.Add(new Line3d(blLast.Clone(), blLast.Add(new Vector3(0,width - stepWidth+ riserThickness, 0)).Clone()));
            bltCurves.Add(new Line3d(blLast.Clone(), blLast.Add(new Vector3(0, 0, -ptxHeight+ 200)).Clone()));
            bltCurves.Add(new Line3d(blLast.Clone(), blLast.Add(new Vector3(0, - width- riserThickness, 0)).Clone()));
            blCurves.AddRange(bltCurves.Select(n => n.Reverse()).Reverse());
            trCurves = tlCurves.Select(n=>n.Clone().Translate(ladderLen,0,0)).ToList();
            var sp = tlCurves.Last().End.Clone().AddScaledVector(new Vector3(0, 0, 1), ptxHeight);
            var ep = tlCurves.First().Start.Clone().AddScaledVector(new Vector3(0, 0, 1), ptxHeight);
            tlCurves.Add(new Line3d(tlCurves.Last().End.Clone(), sp));
            tlCurves.Add(new Line3d(sp, ep));
            tlCurves.Add(new Line3d(ep, tlCurves.First().Start.Clone()));
            blCurves.Add(new Line3d(blCurves.Last().End.Clone(), blCurves.First().Start.Clone()));
            var trLast = trCurves.Last().End.Clone();
            var tTopCurves = new List<Curve3d>();//上梯段顶部碰头线 
            var tFrontCurves = new List<Curve3d>();//上梯段正面碰头线 
            tTopCurves.Add(new Line3d(sp.Clone(),ep.Clone()));
            tTopCurves.Add(new Line3d(ep.Clone(), ep.Clone().Add(new Vector3(ladderLen,0,0))));
            tTopCurves.Add(new Line3d(ep.Clone().Add(new Vector3(ladderLen, 0, 0)), sp.Clone().Add(new Vector3(ladderLen, 0, 0))));
            tTopCurves.Add(new Line3d(sp.Clone().Add(new Vector3(ladderLen, 0, 0)), sp.Clone()));
            tFrontCurves.Add(new Line3d(ep.Clone(), ep.Clone().Add(new Vector3(ladderLen, 0, 0))));
            tFrontCurves.Add(new Line3d(ep.Clone().Add(new Vector3(ladderLen, 0, 0)), ep.Clone().Add(new Vector3(ladderLen, 0, -ptxHeight))));
            tFrontCurves.Add(new Line3d(ep.Clone().Add(new Vector3(ladderLen, 0, -ptxHeight)), ep.Clone().Add(new Vector3(0, 0, -ptxHeight))));
            tFrontCurves.Add(new Line3d(ep.Clone().Add(new Vector3(0, 0, -ptxHeight)), ep.Clone()));
            trCurves.Add(new Line3d(trLast.Clone(), trLast.Add(new Vector3(0,0,-stepHeight)).Clone()));
            trCurves.Add(new Line3d(trLast.Clone(), trLast.Add(new Vector3(0,width-riserThickness,0)).Clone()));
            trCurves.Add(new Line3d(trLast.Clone(), trLast.Add(new Vector3(0, 0, ptxHeight - 200)).Clone()));
            trCurves.Add(new Line3d(trLast.Clone(), trLast.Add(new Vector3(0, stepWidth - width + riserThickness, 0)).Clone()));
            trCurves.Add(new Line3d(trLast.Clone(), trLast.Add(new Vector3(0, 0, stepHeight+ 200)).Clone()));
            trCurves.Add(new Line3d(trLast.Clone(), trLast.Add(new Vector3(0, -stepWidth, 0 )).Clone()));
            trCurves.Add(new Line3d(trLast.Clone(), trCurves.First().Start.Clone().Add(new Vector3(0,0,ptxHeight))));
            trCurves.Add(new Line3d(trCurves.First().Start.Clone().Add(new Vector3(0, 0, ptxHeight)), trCurves.First().Start.Clone()));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(-1, 0, 0)), tlCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(-1, 0, 0)), blCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(1, 0, 0)), trCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(0, -1, 0)), tFrontCurves));
            surfaces.Add(new PlanarSurface3d(new Plane(ep.Clone().Sub(sp).Cross(new Vector3(1,0,0)).Normalize()), tTopCurves));

            
            var posArr = new ListEx<double>();
            var idxArr = new ListEx<int>();
            int idxOffset = 0;
            for (int i = 0; i < surfaces.Count; i++)
            {
                var face = surfaces[i];
                var tuple = face.Trianglate();
                posArr.AddRange(tuple.Item1);
                idxArr.AddRange(tuple.Item2.Select(idx => idx + idxOffset));
                idxOffset += tuple.Item1.Length / 3;
            }
            GeometryData geometryData = new GeometryData();
            geometryData.Position = posArr;
            geometryData.Index = idxArr;
            var geo = geometryData.GetBufferGeometry();
            geo.name = "PTX";
            return geo;
        }
        private LightCAD.Three.BufferGeometry CreateLadder(double stepHeight, int stepNum, double stepWidth, double ladderLen, double slabThickness, double topOffset,double bottomOffset)
        {
            var poly = new ListEx<Vector2>();
            poly.Push(new Vector2(0, 0));
            for (int i = 0; i < stepNum; i++)
            {
                var x = i * stepWidth ;
                var y = (i + 1) * stepHeight;
                poly.Push(new Vector2(x, y), new Vector2(x + stepWidth, y));
            }
            var p0 = poly[2];
            var p2 = poly[4];
            var obliqueDir = new Vector2(stepWidth,stepHeight).Normalize();
            var offsetDir = obliqueDir.Clone().RotateAround(new Vector2(), -Math.PI / 2);
            var sp = new Vector2().AddScaledVector(offsetDir, slabThickness);
            sp = CurveUtil.LineIntersectLine2D(sp, obliqueDir.Clone().Negate(), poly.First(), new Vector2(0, -1));
            var ep = CurveUtil.LineIntersectLine2D(sp, obliqueDir, poly.Last(), new Vector2(0, -1));
            //判断平台底部是否低于梯段底部，低于梯段，梯段需要补平
            if (poly.Last().Y + stepHeight + topOffset < ep.Y)
            {
                var newEp = new Vector2(ep.X, poly.Last().Y + stepHeight + topOffset);
                ep = CurveUtil.LineIntersectLine2D(sp, obliqueDir, newEp, new Vector2(-1, 0));
                poly.Push(newEp, ep);
            }
            if (sp.Y < bottomOffset)
            {
                var newSp = CurveUtil.LineIntersectLine2D(sp, obliqueDir, new Vector2(0, bottomOffset), new Vector2(1, 0));
                poly.Push(ep.Clone(), newSp);
                ep = newSp.Clone();
                sp = new Vector2(0, bottomOffset);
            }
 
            poly.Push(ep, sp);
            poly.Reverse();
            var shape = new LightCAD.Three.Shape(poly);
            var coodMat = new Matrix4();
            coodMat.MakeBasis(new Vector3(0, 1, 0), new Vector3(0, 0, 1), new Vector3(1, 0, 0));
            var geo = GeoUtil.GetStretchGeometryData(shape, coodMat, ladderLen, 0).GetBufferGeometry();
            geo.name = "Ladder";
            return geo;
        }
        private LightCAD.Three.BufferGeometry CreatePlat(double stepHeight, int stepNum, double stepWidth, double ladderLen, double slabThickness,  double len, double width, double thickness)
        {
            var obliqueDir = new Vector2(stepWidth, stepHeight).Normalize();
            var offsetDir = obliqueDir.Clone().RotateAround(new Vector2(), -Math.PI / 2);
            var sp = new Vector2().AddScaledVector(offsetDir, slabThickness);
            sp = CurveUtil.LineIntersectLine2D(sp, obliqueDir , new Vector2(stepWidth*stepNum,0),new Vector2(0,1));

            var rightObliqueDir = new Vector2(-stepWidth, stepHeight).Normalize();
            var rightOffsetDir = rightObliqueDir.Clone().RotateAround(new Vector2(), Math.PI / 2);
            var rightSp = new Vector2(0,thickness).Clone().AddScaledVector(rightOffsetDir, slabThickness);
            rightSp = CurveUtil.LineIntersectLine2D(rightSp, rightObliqueDir.Clone().Negate(), new Vector2(0,thickness), new Vector2(0, -1));
            //判断右侧梯段底面最低点高度是否低于平台底面高度
            bool isRightLow = rightSp.Y < 0;
            //判断左侧梯段底面顶点高度是否低于平台底面高度
            bool isLeftLow = stepHeight * (stepNum + 1)- thickness > sp.Height;
            var surfaces = new List<Surface3d>();

            //平台基础六面
            var frontCurves = new List<Curve3d>();//正面 连接梯段面
            var topCurves = new List<Curve3d>();//顶面 踏面
            var bottomCurves = new List<Curve3d>();//底面
            var rightCurves = new List<Curve3d>();// 右侧连接上梯段侧面
            var leftCurves = new List<Curve3d>();// 左侧连接下梯段侧面                                               
            var backCurve = new List<Curve3d>(); //转角侧面

            backCurve.Add(new Line3d(new Vector3(0, width, 0), new Vector3(0, width, thickness)));
            backCurve.Add(new Line3d(new Vector3(0, width, thickness), new Vector3(len, width, thickness)));
            backCurve.Add(new Line3d(new Vector3(len, width, thickness), new Vector3(len, width, 0)));
            backCurve.Add(new Line3d(new Vector3(len, width, 0), new Vector3(0, width, 0)));

            bottomCurves.Add(new Line3d(new Vector3(0,width,0), new Vector3(len,width,0)));
            frontCurves.Add(new Line3d(new Vector3(0, 0, thickness), new Vector3(len, 0, thickness)));

            topCurves.Add(new Line3d(new Vector3(0, 0, thickness), new Vector3(len, 0, thickness)));
            topCurves.Add(new Line3d(new Vector3(len, 0, thickness), new Vector3(len, width, thickness)));
            topCurves.Add(new Line3d(new Vector3(len, width, thickness), new Vector3(0, width, thickness)));
            topCurves.Add(new Line3d(new Vector3(0, width, thickness), new Vector3(0, 0, thickness)));


            var rightCp = CurveUtil.LineIntersectLine2D(new Vector2(0, rightSp.Y), rightObliqueDir.Clone().Negate(), new Vector2(0, thickness), new Vector2(0, -1));
            var rbCp = CurveUtil.LineIntersectLine2D(new Vector2(0, rightSp.Y), rightObliqueDir.Clone().Negate(), new Vector2(width, 0), new Vector2(-1, 0));

            //有踢面时右侧梯段连接正面
            var frontRightCurves = new List<Curve3d>();
            //平台右侧梯段连接踢面内嵌侧面
            var riserRightCurves = new List<Curve3d>();

            if (isRightLow)
            {
                frontCurves.Add(new Line3d(new Vector3(len, 0, thickness), new Vector3(len, 0, 0)));
                frontCurves.Add(new Line3d(new Vector3(len, 0, 0), new Vector3(ladderLen, 0, 0)));

                rightCurves.Add(new Line3d(new Vector3(len, 0, 0), new Vector3(len, 0, thickness)));
                rightCurves.Add(new Line3d(new Vector3(len, 0, thickness), new Vector3(len, width, thickness)));
                rightCurves.Add(new Line3d(new Vector3(len, width, thickness), new Vector3(len, width, 0)));
                rightCurves.Add(new Line3d(new Vector3(len, width, 0), new Vector3(len, 0, 0)));

                bottomCurves.Add(new Line3d(new Vector3(len, width, 0), new Vector3(len, 0, 0)));
                bottomCurves.Add(new Line3d(new Vector3(len, 0, 0), new Vector3(len - ladderLen, 0, 0)));
                bottomCurves.Add(new Line3d(new Vector3(len - ladderLen, 0, 0), new Vector3(len - ladderLen, 0, 0)));

            }
            else
            {
                frontCurves.Add(new Line3d(new Vector3(len, 0, thickness), new Vector3(len, 0, rightSp.Y)));
                frontCurves.Add(new Line3d(new Vector3(len, 0, rightSp.Y), new Vector3(len - ladderLen, 0, rightSp.Y)));
                frontCurves.Add(new Line3d(new Vector3(len - ladderLen, 0, rightSp.Y), new Vector3(len - ladderLen, 0, 0)));
                frontCurves.Add(new Line3d(new Vector3(len - ladderLen, 0, 0), new Vector3(ladderLen, 0, 0)));

                rightCurves.Add(new Line3d(new Vector3(len, 0, rightSp.Y), new Vector3(len, 0, thickness)));
                rightCurves.Add(new Line3d(new Vector3(len, 0, thickness), new Vector3(len, width, thickness)));
                rightCurves.Add(new Line3d(new Vector3(len, width, thickness), new Vector3(len, width, 0)));
                rightCurves.Add(new Line3d(new Vector3(len, width, 0), new Vector3(len, rbCp.X, 0)));
                rightCurves.Add(new Line3d(new Vector3(len, rbCp.X, 0), new Vector3(len, 0, rightSp.Y)));
                //平台接右侧梯段底面 斜面补充
                var rightBottomCurves = new List<Curve3d>();
                rightBottomCurves.Add(new Line3d(new Vector3(len, rbCp.X, 0), new Vector3(len, 0, rightSp.Y)));
                rightBottomCurves.Add(new Line3d(new Vector3(len, 0, rightSp.Y), new Vector3(len - ladderLen, 0, rightSp.Y)));
                rightBottomCurves.Add(new Line3d(new Vector3(len - ladderLen, 0, rightSp.Y), new Vector3(len - ladderLen, rbCp.X, 0)));
                rightBottomCurves.Add(new Line3d(new Vector3(len - ladderLen, rbCp.X, 0), new Vector3(len, rbCp.X, 0)));
                var rbcNormal = new Vector3(0, -stepWidth, stepHeight).Cross(new Vector3(1, 0, 0)).Negate().Normalize();
                surfaces.Add(new PlanarSurface3d(new Plane(rbcNormal), rightBottomCurves));
                //当右侧梯段底面 斜面与平台底面交点在平台内，平台内右侧需补上一个三角面
                if (rbCp.X > 0)
                {
                    var rightTriangleCurves = new List<Curve3d>();
                    rightTriangleCurves.Add(new Line3d(new Vector3(len - ladderLen, 0, 0), new Vector3(len - ladderLen, 0, rightCp.Y)));
                    rightTriangleCurves.Add(new Line3d(new Vector3(len - ladderLen, 0, rightCp.Y), new Vector3(len - ladderLen, rbCp.X, 0)));
                    rightTriangleCurves.Add(new Line3d(new Vector3(len - ladderLen, rbCp.X, 0), new Vector3(len - ladderLen, 0, 0)));
                    surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(1, 0, 0)), rightTriangleCurves));
                }
                bottomCurves.Add(new Line3d(new Vector3(len, width, 0), new Vector3(len, rbCp.X, 0)));
                bottomCurves.Add(new Line3d(new Vector3(len, rbCp.X, 0), new Vector3(len - ladderLen, rbCp.X, 0)));
                bottomCurves.Add(new Line3d(new Vector3(len - ladderLen, rbCp.X, 0), new Vector3(len - ladderLen, 0, 0)));
            }

            bottomCurves.Add(new Line3d(new Vector3(len - ladderLen, 0, 0), new Vector3(ladderLen, 0, 0)));

            if (isLeftLow)
            {
                var platZ = sp.Height - (stepHeight * (stepNum + 1)  - thickness);
                var cp = CurveUtil.LineIntersectLine2D(new Vector2(0, platZ), obliqueDir, new Vector2(), new Vector2(1, 0));
                leftCurves.Add(new Line3d(new Vector3(0, 0, platZ),new Vector3(0, 0, thickness)));
                leftCurves.Add(new Line3d( new Vector3(0, 0, thickness), new Vector3(0, width, thickness)));
                leftCurves.Add(new Line3d(new Vector3(0, width, thickness), new Vector3(0, width, 0)));
                leftCurves.Add(new Line3d(new Vector3(0, width, 0), new Vector3(0, cp.X, 0)));
                leftCurves.Add(new Line3d(new Vector3(0, cp.X, 0), new Vector3(0, 0, platZ)));
                //平台连接左侧梯段平滑过渡倾斜面
                var bInclineCurves =  new List<Curve3d>();
                bInclineCurves.Add(new Line3d(new Vector3(0, 0, platZ), new Vector3(ladderLen, 0, platZ)));
                bInclineCurves.Add(new Line3d(new Vector3(ladderLen, 0, platZ), new Vector3(ladderLen,cp.X,0)));
                bInclineCurves.Add(new Line3d(new Vector3(ladderLen, cp.X, 0), new Vector3(0,cp.X,0)));
                bInclineCurves.Add(new Line3d(new Vector3(0, cp.X, 0), new Vector3(0, 0, platZ)));
                var normal = bInclineCurves[1].End.Clone().Sub(bInclineCurves[1].Start).Cross(new Vector3(0,1,0)).Normalize();
                surfaces.Add(new PlanarSurface3d(new Plane(normal), bInclineCurves));
                //平台连接左侧梯段平滑过渡 右侧三角形面
                var triangleCurves = new List<Curve3d>();
                triangleCurves.Add(new Line3d(new Vector3(ladderLen, 0, platZ), new Vector3(ladderLen, cp.X, 0)));
                triangleCurves.Add(new Line3d(new Vector3(ladderLen, cp.X, 0), new Vector3(ladderLen, 0, 0)));
                triangleCurves.Add(new Line3d(new Vector3(ladderLen, 0, 0), new Vector3(ladderLen, 0, platZ)));
                surfaces.Add(new PlanarSurface3d(new Plane(new Vector3(1,0,0)), triangleCurves));
                frontCurves.Add(new Line3d(new Vector3(ladderLen, 0, 0), new Vector3(ladderLen, 0, platZ)));
                frontCurves.Add(new Line3d(new Vector3(ladderLen, 0, platZ), new Vector3(0, 0, platZ)));
                frontCurves.Add(new Line3d(new Vector3(0, 0, platZ), new Vector3(0, 0, thickness)));

                bottomCurves.Add(new Line3d( new Vector3(ladderLen, 0, 0), new Vector3(ladderLen, cp.X, 0)));
                bottomCurves.Add(new Line3d(new Vector3(ladderLen, cp.X, 0), new Vector3(0, cp.X, 0)));
                bottomCurves.Add(new Line3d(new Vector3(0, cp.X, 0), new Vector3(0, width, 0)));

            }
            else
            {
                leftCurves.Add(new Line3d(new Vector3(0, 0, 0), new Vector3(0, 0, thickness)));
                leftCurves.Add(new Line3d(new Vector3(0, 0, thickness), new Vector3(0, width, thickness)));
                leftCurves.Add(new Line3d(new Vector3(0, width, thickness), new Vector3(0, width, 0)));
                leftCurves.Add(new Line3d(new Vector3(0, width, 0), new Vector3(0, 0, 0)));
                bottomCurves.Add(new Line3d(new Vector3(ladderLen, 0, 0), new Vector3(0, 0, 0)));
                bottomCurves.Add(new Line3d(new Vector3(0, 0, 0), new Vector3(0, width, 0)));

                frontCurves.Add(new Line3d(new Vector3(ladderLen, 0, 0), new Vector3(0, 0, 0)));
                frontCurves.Add(new Line3d(new Vector3(0, 0, 0), new Vector3(0, 0, thickness)));

            }

            var backFace = new PlanarSurface3d(new Plane(new Vector3(0, 1, 0)), backCurve);
            surfaces.Add(backFace);
            var topFace = new PlanarSurface3d(new Plane(new Vector3(0, 0, 1)), topCurves);
            surfaces.Add(topFace);
            var rightFace = new PlanarSurface3d(new Plane(new Vector3(1, 0, 0)), rightCurves);
            surfaces.Add(rightFace);
            var frontFace = new PlanarSurface3d(new Plane(new Vector3(0, -1, 0)), frontCurves);
            surfaces.Add(frontFace);
            var leftFace = new PlanarSurface3d(new Plane(new Vector3(-1, 0, 0)), leftCurves);
            surfaces.Add(leftFace);
            var bottomFace = new PlanarSurface3d(new Plane(new Vector3(0, 0, -1)), bottomCurves);
            surfaces.Add(bottomFace);
            var posArr = new ListEx<double>();
            var idxArr = new ListEx<int>();
            int idxOffset = 0;
            for (int i = 0; i < surfaces.Count; i++)
            {
                var face = surfaces[i];
                var tuple = face.Trianglate();
                posArr.AddRange(tuple.Item1);
                idxArr.AddRange(tuple.Item2.Select(idx => idx + idxOffset));
                idxOffset += tuple.Item1.Length / 3;
            }
            GeometryData geometryData = new GeometryData();
            geometryData.Position = posArr;
            geometryData.Index = idxArr;
            var geo = geometryData.GetBufferGeometry() ;
            geo.name = "Plat";
            return geo;
        }
 
        private LightCAD.Three.BufferGeometry CreateLadderStep( double stepWidth, double ladderLen , double stepThickness)
        {
            var poly = new ListEx<Vector2>();
            poly.Push(new Vector2(0, 0));
            poly.Push(new Vector2(ladderLen, 0));
            poly.Push(new Vector2(ladderLen, stepWidth));
            poly.Push(new Vector2(0, stepWidth));
            var shape = new LightCAD.Three.Shape(poly);
            var coodMat = new Matrix4();
            coodMat.MakeBasis(new Vector3(1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 1));
            var geo = GeoUtil.GetStretchGeometryData(shape, coodMat, stepThickness, 0).GetBufferGeometry();
            geo.name = "Step";
            return geo;
        }
        private LightCAD.Three.BufferGeometry CreatePlatStep(double len, double width, double thickness, double ladderLen, double riserThickness)
        {
            var poly = new ListEx<Vector2>();
            poly.Push(new Vector2(0, - riserThickness));
            poly.Push(new Vector2(ladderLen, -riserThickness));
            poly.Push(new Vector2(ladderLen, 0));
            poly.Push(new Vector2(len-ladderLen, 0));
            poly.Push(new Vector2(len - ladderLen, riserThickness));
            poly.Push(new Vector2(len, riserThickness));
            poly.Push(new Vector2(len, width));
            poly.Push(new Vector2(0, width));
            var shape = new LightCAD.Three.Shape(poly);
            var coodMat = new Matrix4();
            coodMat.MakeBasis(new Vector3(1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 1));
            var geo = GeoUtil.GetStretchGeometryData(shape, coodMat, thickness, 0).GetBufferGeometry();
            geo.name = "Step";
            return geo;
        }
        private LightCAD.Three.BufferGeometry CreateRiser(double stepHeight, double ladderLen,  double riserThickness)
        {
            var poly = new ListEx<Vector2>();
            poly.Push(new Vector2(0, 0));
            poly.Push(new Vector2(ladderLen, 0));
            poly.Push(new Vector2(ladderLen, stepHeight));
            poly.Push(new Vector2(0, stepHeight));
            var shape = new LightCAD.Three.Shape(poly);
            var coodMat = new Matrix4();
            coodMat.MakeBasis(new Vector3(1, 0, 0), new Vector3(0, 0, -1), new Vector3(0, 1, 0));
            var geo = GeoUtil.GetStretchGeometryData(shape, coodMat, riserThickness, 0).GetBufferGeometry();
            geo.name = "Riser";
            return geo;
        }

        private LightCAD.Three.BufferGeometry CreateFirstRiser(double stepHeight, double ladderLen, double riserThickness,double stepThickness)
        {
            var poly = new ListEx<Vector2>();
            poly.Push(new Vector2(0, 0));
            poly.Push(new Vector2(ladderLen, 0));
            poly.Push(new Vector2(ladderLen, stepHeight));
            poly.Push(new Vector2(0, stepHeight));
            var shape = new LightCAD.Three.Shape(poly);
            var coodMat = new Matrix4();
            coodMat.MakeBasis(new Vector3(1, 0, 0), new Vector3(0, 0, -1), new Vector3(0, 1, 0));
            var geo = GeoUtil.GetStretchGeometryData(shape, coodMat, riserThickness, 0).GetBufferGeometry();
            geo.name = "Riser";
            return geo;
        }

    }
}
